/**
 * https://blog.csdn.net/weixin_43443913/article/details/140479283
 */

package com.cloud.xtools.common.util;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.function.Function;


/**
 * @author Daixinguo
 */
@Component
public class JwtUtil {

    @Value("${jwt.secret}")
    private String secret;

    @Value("${jwt.expiration}")
    private long expirationTime;

    // 创建 token
    public String createToken(Long id, String username) {
        final var signKey = Keys.hmacShaKeyFor(secret.getBytes());
        //jws生成部分
        return Jwts.builder()
                .subject(username)
                .claim("user_id", id)
                .issuedAt(new Date(System.currentTimeMillis()))
                .expiration(new Date(System.currentTimeMillis() + expirationTime))
                .signWith(signKey)
                .id(username + "_" + System.currentTimeMillis())
                .compact();
    }

    // 验证 token
    public boolean validateToken(String token, String username) {
        final String extractedUsername = extractUsername(token);
        return (extractedUsername.equals(username) && !isTokenExpired(token));
    }

    // 获取（subject） username
    public String extractUsername(String token) {

        return extractClaim(token, Claims::getSubject);
    }

    // 获取 user_id
    public Object getUserId(String token) {
        final Claims claims = extractAllClaims(token);
        return claims.get("user_id");
    }

    // 获取（claim） id
    public String extractId(String token) {

        return extractClaim(token, Claims::getId);
    }

    // 获取过期时间
    public Date extractExpiration(String token) {

        return extractClaim(token, Claims::getExpiration);
    }

    // 获取 Claims 中指定属性的值
    public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) {

        final Claims claims = extractAllClaims(token);
        return claimsResolver.apply(claims);
    }

    // 获取所有 claim
    public Claims extractAllClaims(String token) {
        try {
            final var signKey = Keys.hmacShaKeyFor(secret.getBytes());
            return Jwts.parser()
                    .verifyWith(signKey)
                    .build()
                    .parseSignedClaims(token)
                    .getPayload();
        } catch (ExpiredJwtException e) {
            // System.out.println(e.getMessage());
            // System.out.println(e.getClaims());
            // 当 token 过期的时候这里也会抛出异常 但是这样就无法在 isTokenExpired 中获取到过期时间用于检查
            return e.getClaims();
        }
    }

    // Token 是否过期
    public boolean isTokenExpired(String token) {

        return extractExpiration(token).before(new Date());
    }
}
